Setup notebook

The following libraries are used in for in this notebook:

# Load libraries
library(tidyverse)
library(tidymodels)
library(readr)
library(glmnet)
package 㤼㸱glmnet㤼㸲 was built under R version 4.0.3
library(leaps)
package 㤼㸱leaps㤼㸲 was built under R version 4.0.3
library(naniar)
package 㤼㸱naniar㤼㸲 was built under R version 4.0.3
library(skimr)
package 㤼㸱skimr㤼㸲 was built under R version 4.0.3
library(knitr)
library(corrplot)
package 㤼㸱corrplot㤼㸲 was built under R version 4.0.3

Load data listings

# Read csv with listing information
data <- read_csv(gzfile("listings.csv.gz"))
38 parsing failures.
  row     col           expected         actual         file
15026 license 1/0/T/F/TRUE/FALSE NL857416819B01 <connection>
15673 license 1/0/T/F/TRUE/FALSE NL825517485B01 <connection>
15961 license 1/0/T/F/TRUE/FALSE NL825517485B01 <connection>
16391 license 1/0/T/F/TRUE/FALSE 855596338B01   <connection>
16823 license 1/0/T/F/TRUE/FALSE NL854649426B01 <connection>
..... ....... .................. .............. ............
See problems(...) for more details.

Select variables of interest

The goal of the assignment is to build a model that predicts the prices of listings on AirBnB in Amsterdam. The outcomes of the model will be used for suggestions to the new hosts about the average platform price for similar listings. Then hosts can choose whether they want to use the recommendation to set their prices accordingly in order to be competitive and gain attention from the guests since the beginning. All variables including information on the reviews give information about a listing after it has been published. Therefore, this variables are not included in the data set. Moreover, the variables including a description and summary about the listing can be analyzed using NLP (e.g. sentiment analysis). However, this is beyond the scope of the assignment. Therefore, these variables are excluded from the model. The variables below are included in the data set for further analysis and cleaning.

# Generate subset with variables of interest
data_sub <- data %>%
  select(id, price, property_type, room_type, accommodates, bathrooms, bedrooms,
         beds, bed_type, amenities, host_since, host_response_time,
         host_response_rate, host_neighbourhood, host_listings_count, 
         host_verifications, host_identity_verified, neighbourhood_cleansed,
         square_feet, cleaning_fee, guests_included, extra_people, 
         minimum_nights, maximum_nights, availability_30, availability_60,
         availability_90, availability_365, instant_bookable, 
         cancellation_policy, require_guest_profile_picture,
         require_guest_phone_verification, calculated_host_listings_count,
         calculated_host_listings_count_entire_homes, 
         calculated_host_listings_count_private_rooms,
         calculated_host_listings_count_shared_rooms)
# Inspect data
head(data_sub)
<<<<<<< HEAD ======= >>>>>>> fc0442fd76290b6483426e318740d6bc774d6ae0
# Inspect data
skim(data_sub) %>% knit_print()
Name data_sub
Number of rows 20025
Number of columns 36
_______________________
Column type frequency:
character 13
Date 1
logical 4
numeric 18
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
price 0 1.00 5 9 0 479 0
property_type 0 1.00 3 22 0 34 0
room_type 0 1.00 10 15 0 4 0
bed_type 0 1.00 5 13 0 5 0
amenities 0 1.00 2 1303 0 19213 0
host_response_time 158 0.99 3 18 0 5 0
host_response_rate 158 0.99 2 4 0 61 0
host_neighbourhood 5972 0.70 4 35 0 81 0
host_verifications 0 1.00 2 158 0 381 0
neighbourhood_cleansed 0 1.00 4 38 0 22 0
cleaning_fee 3604 0.82 5 7 0 112 0
extra_people 0 1.00 5 7 0 112 0
cancellation_policy 0 1.00 8 27 0 5 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
host_since 158 0.99 2008-09-24 2019-12-06 2015-02-08 3133

Variable type: logical

skim_variable n_missing complete_rate mean count
host_identity_verified 158 0.99 0.39 FAL: 12094, TRU: 7773
instant_bookable 0 1.00 0.26 FAL: 14839, TRU: 5186
require_guest_profile_picture 0 1.00 0.01 FAL: 19819, TRU: 206
require_guest_phone_verification 0 1.00 0.01 FAL: 19758, TRU: 267

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
id 0 1.00 19117026.00 11473019.80 2818 9631819 18418621 27913527.0 40655209 ▇▇▇▅▆
accommodates 0 1.00 2.87 1.30 1 2 2 4.0 18 ▇▁▁▁▁
bathrooms 6 1.00 1.18 0.39 0 1 1 1.5 8 ▇▁▁▁▁
bedrooms 13 1.00 1.45 0.89 0 1 1 2.0 12 ▇▁▁▁▁
beds 31 1.00 1.79 1.41 0 1 1 2.0 32 ▇▁▁▁▁
host_listings_count 158 0.99 3.85 28.93 0 1 1 1.0 751 ▇▁▁▁▁
square_feet 19662 0.02 542.88 560.24 0 0 484 834.0 3229 ▇▅▁▁▁
guests_included 0 1.00 1.46 0.95 1 1 1 2.0 16 ▇▁▁▁▁
minimum_nights 0 1.00 3.43 14.74 1 2 2 3.0 1001 ▇▁▁▁▁
maximum_nights 0 1.00 613.89 548.62 1 20 1125 1125.0 11250 ▇▁▁▁▁
availability_30 0 1.00 4.46 7.81 0 0 0 6.0 30 ▇▁▁▁▁
availability_60 0 1.00 10.05 17.14 0 0 0 13.0 60 ▇▁▁▁▁
availability_90 0 1.00 15.69 26.77 0 0 0 19.0 90 ▇▁▁▁▁
availability_365 0 1.00 47.93 95.34 0 0 0 37.0 365 ▇▁▁▁▁
calculated_host_listings_count 0 1.00 1.97 5.20 1 1 1 1.0 72 ▇▁▁▁▁
calculated_host_listings_count_entire_homes 0 1.00 1.50 5.06 0 1 1 1.0 72 ▇▁▁▁▁
calculated_host_listings_count_private_rooms 0 1.00 0.38 1.08 0 0 0 0.0 16 ▇▁▁▁▁
calculated_host_listings_count_shared_rooms 0 1.00 0.01 0.09 0 0 0 0.0 3 ▇▁▁▁▁

Data cleaning

Basic cleaning

First, we converted all categorical en logical variables, that did not need any further cleaning, to type factors.

# Convert columns to factors 
data_sub$property_type <- factor(data_sub$property_type , 
                                 levels = unique(data_sub$property_type))
data_sub$room_type <- factor(data_sub$room_type , 
                             levels = unique(data_sub$room_type))
data_sub$bed_type <- factor(data_sub$bed_type , 
                    levels = unique(data_sub$bed_type))
data_sub$host_response_time <- factor(data_sub$ host_response_time, 
                    levels = unique(data_sub$host_response_time))
data_sub$host_neighbourhood <- factor(data_sub$host_neighbourhood, 
                    levels = unique(data_sub$host_neighbourhood))
data_sub$neighbourhood_cleansed <- factor(data_sub$neighbourhood_cleansed, 
                    levels = unique(data_sub$neighbourhood_cleansed))
data_sub$cancellation_policy <- factor(data_sub$cancellation_policy , 
                    levels = unique(data_sub$cancellation_policy))

# Convert logical variables to factors
data_sub$host_identity_verified <- factor(data_sub$host_identity_verified)
data_sub$instant_bookable <- factor(data_sub$instant_bookable)
data_sub$require_guest_profile_picture <- 
  factor(data_sub$require_guest_profile_picture)
data_sub$require_guest_phone_verification <- 
  factor(data_sub$require_guest_phone_verification)

Second, some of the variables contain numeric variables, however, they are stored in a string containing a dollar or percentage sign. The signs we removed from the strings and the remaining number converted to numeric variables.

# Remove $ sign from columns containing prices and convert to doubles
data_sub$price <- as.double(gsub("[,$]", "", data_sub$price))
data_sub$cleaning_fee <- as.double(gsub("[,$]", "", data_sub$cleaning_fee))
data_sub$extra_people <- as.double(gsub("[,$]", "", data_sub$extra_people))

# Replace "N/A" values, remove % and convert to percentage 
data_sub$host_response_rate <- na_if(data_sub$host_response_rate, "N/A")
data_sub$host_response_rate <- 
  as.double(gsub("[%]", "", data_sub$host_response_rate)) / 100

Clean amenities

The variable amenities contains all the amenities of the listing. However, this was stored in one large string and the elements could not be access separately. Therefore, we cleaned the string, spitted it so we had a list containing the separated elements. Furthermore, we extracted all unique amenities and stored these in a vector.

# Clean and split strings for amenities
# Returns a list with all unique values
clean_amenities <- function(x) {
  subbed <- gsub('[{}\"]', "", tolower(x))
  splitted <- str_split(subbed, ",")
  clean <- sapply(splitted, function(x) str_trim(x, side = "both"))
  return(clean)
}

# Clean amenities
data_sub$amenities_clean <- 
  sapply(data_sub$amenities, function(x) clean_amenities(x))

# Create vector with all unique amenities
amenities_unique = c()
for(amenities in data_sub$amenities_clean) {
  for(element in amenities) {
    if(!(element %in% amenities_unique) & element != "") {
      amenities_unique <- append(amenities_unique, str_trim(element))
    }
  }
}

# Show result
amenities_unique
<<<<<<< HEAD
  [1] "internet"                                   "wifi"                                       "paid parking off premises"                 
  [4] "buzzer/wireless intercom"                   "heating"                                    "washer"                                    
  [7] "smoke detector"                             "carbon monoxide detector"                   "first aid kit"                             
 [10] "safety card"                                "fire extinguisher"                          "essentials"                                
 [13] "shampoo"                                    "lock on bedroom door"                       "24-hour check-in"                          
 [16] "hangers"                                    "hair dryer"                                 "iron"                                      
 [19] "laptop friendly workspace"                  "translation missing: en.hosting_amenity_49" "translation missing: en.hosting_amenity_50"
 [22] "private entrance"                           "hot water"                                  "bed linens"                                
 [25] "extra pillows and blankets"                 "single level home"                          "garden or backyard"                        
 [28] "no stairs or steps to enter"                "accessible-height bed"                      "host greets you"                           
 [31] "handheld shower head"                       "paid parking on premises"                   "tv"                                        
 [34] "refrigerator"                               "long term stays allowed"                    "cable tv"                                  
 [37] "kitchen"                                    "elevator"                                   "indoor fireplace"                          
 [40] "family/kid friendly"                        "dryer"                                      "private living room"                       
 [43] "well-lit path to entrance"                  "breakfast"                                  "self check-in"                             
 [46] "smart lock"                                 "lake access"                                "pets live on this property"                
 [49] "cat(s)"                                     "smoking allowed"                            "pets allowed"                              
 [52] "microwave"                                  "coffee maker"                               "dishwasher"                                
 [55] "dishes and silverware"                      "cooking basics"                             "oven"                                      
 [58] "stove"                                      "patio or balcony"                           "keypad"                                    
 [61] "luggage dropoff allowed"                    "baby bath"                                  "bathtub"                                   
 [64] "babysitter recommendations"                 "beach essentials"                           "cleaning before checkout"                  
 [67] "ev charger"                                 "pack ’n play/travel crib"                   "high chair"                                
 [70] "crib"                                       "children’s books and toys"                  "room-darkening shades"                     
 [73] "children’s dinnerware"                      "free street parking"                        "other"                                     
 [76] "extra space around bed"                     "wheelchair accessible"                      "pocket wifi"                               
 [79] "wide hallways"                              "waterfront"                                 "washer / dryer"                            
 [82] "window guards"                              "air conditioning"                           "suitable for events"                       
 [85] "free parking on premises"                   "lockbox"                                    "wide entrance for guests"                  
 [88] "bbq grill"                                  "ground floor access"                        "dog(s)"                                    
 [91] "hot tub"                                    "wide entrance"                              "accessible-height toilet"                  
 [94] "wide entryway"                              "hot water kettle"                           "ethernet connection"                       
 [97] "flat path to guest entrance"                "wide doorway to guest bathroom"             "wide clearance to shower"                  
[100] "toilet"                                     "step-free shower"                           "gym"                                       
[103] "outlet covers"                              "firm mattress"                              "changing table"                            
[106] "stair gates"                                "fireplace guards"                           "table corner guards"                       
[109] "game console"                               "baby monitor"                               "doorman"                                   
[112] "building staff"                             "pool"                                       "other pet(s)"                              
[115] "fixed grab bars for shower"                 "disabled parking spot"                      "electric profiling bed"                    
[118] "bathtub with bath chair"                    "shower gel"                                 "fixed grab bars for toilet"                
[121] "beachfront"                                 "shower chair"                               "trash can"                                 
[124] "ski-in/ski-out"                             "mobile hoist"                               "pool with pool hoist"                      
[127] "ceiling hoist"                              "full kitchen"                               "private bathroom"                          
[130] "air purifier"                               "bread maker"                                "roll-in shower with chair"                 
=======
  [1] "internet"                                   "wifi"                                       "paid parking off premises"                  "buzzer/wireless intercom"                  
  [5] "heating"                                    "washer"                                     "smoke detector"                             "carbon monoxide detector"                  
  [9] "first aid kit"                              "safety card"                                "fire extinguisher"                          "essentials"                                
 [13] "shampoo"                                    "lock on bedroom door"                       "24-hour check-in"                           "hangers"                                   
 [17] "hair dryer"                                 "iron"                                       "laptop friendly workspace"                  "translation missing: en.hosting_amenity_49"
 [21] "translation missing: en.hosting_amenity_50" "private entrance"                           "hot water"                                  "bed linens"                                
 [25] "extra pillows and blankets"                 "single level home"                          "garden or backyard"                         "no stairs or steps to enter"               
 [29] "accessible-height bed"                      "host greets you"                            "handheld shower head"                       "paid parking on premises"                  
 [33] "tv"                                         "refrigerator"                               "long term stays allowed"                    "cable tv"                                  
 [37] "kitchen"                                    "elevator"                                   "indoor fireplace"                           "family/kid friendly"                       
 [41] "dryer"                                      "private living room"                        "well-lit path to entrance"                  "breakfast"                                 
 [45] "self check-in"                              "smart lock"                                 "lake access"                                "pets live on this property"                
 [49] "cat(s)"                                     "smoking allowed"                            "pets allowed"                               "microwave"                                 
 [53] "coffee maker"                               "dishwasher"                                 "dishes and silverware"                      "cooking basics"                            
 [57] "oven"                                       "stove"                                      "patio or balcony"                           "keypad"                                    
 [61] "luggage dropoff allowed"                    "baby bath"                                  "bathtub"                                    "babysitter recommendations"                
 [65] "beach essentials"                           "cleaning before checkout"                   "ev charger"                                 "pack ’n play/travel crib"                  
 [69] "high chair"                                 "crib"                                       "children’s books and toys"                  "room-darkening shades"                     
 [73] "children’s dinnerware"                      "free street parking"                        "other"                                      "extra space around bed"                    
 [77] "wheelchair accessible"                      "pocket wifi"                                "wide hallways"                              "waterfront"                                
 [81] "washer / dryer"                             "window guards"                              "air conditioning"                           "suitable for events"                       
 [85] "free parking on premises"                   "lockbox"                                    "wide entrance for guests"                   "bbq grill"                                 
 [89] "ground floor access"                        "dog(s)"                                     "hot tub"                                    "wide entrance"                             
 [93] "accessible-height toilet"                   "wide entryway"                              "hot water kettle"                           "ethernet connection"                       
 [97] "flat path to guest entrance"                "wide doorway to guest bathroom"             "wide clearance to shower"                   "toilet"                                    
[101] "step-free shower"                           "gym"                                        "outlet covers"                              "firm mattress"                             
[105] "changing table"                             "stair gates"                                "fireplace guards"                           "table corner guards"                       
[109] "game console"                               "baby monitor"                               "doorman"                                    "building staff"                            
[113] "pool"                                       "other pet(s)"                               "fixed grab bars for shower"                 "disabled parking spot"                     
[117] "electric profiling bed"                     "bathtub with bath chair"                    "shower gel"                                 "fixed grab bars for toilet"                
[121] "beachfront"                                 "shower chair"                               "trash can"                                  "ski-in/ski-out"                            
[125] "mobile hoist"                               "pool with pool hoist"                       "ceiling hoist"                              "full kitchen"                              
[129] "private bathroom"                           "air purifier"                               "bread maker"                                "roll-in shower with chair"                 
>>>>>>> fc0442fd76290b6483426e318740d6bc774d6ae0

Create new variables based information stored in amenities

With the vector of all unique amenities we could create variables for all the separated variables. However, since there are 130 usable amenities it seemed beyond the scope of the assignment. Moreover, some of the amenities contain information that is also given by other variables or about other amenities. For example a private bathroom could also be a strong indicator that the listing is an entire house/apartment. Also, shampoo or shower gel could be strong indicators for the presence of a bathroom. Furthermore, some are amenities are very specific and apply only to a few or one house. However, we created variables some of the amenities we think could have an influence on the price of a listing. We created variables for wifi, pool, hot_tub and tv.

# Create variable for WIFI and add to data set
wifi <- vector()
for(i in 1:length(data_sub$amenities_clean)) {
  if("wifi" %in% data_sub$amenities_clean[[i]] | 
     "internet" %in% data_sub$amenities_clean[[i]]) {
    wifi[i] <-  "yes"
  } else {
    wifi[i] <-  "no"
  }
}
data_sub$wifi <- wifi
data_sub$wifi <- factor(data_sub$wifi, levels = c("yes", "no"))

# Create variable for pool and add to data set
pool <- vector()
for(i in 1:length(data_sub$amenities_clean)) {
  if("pool" %in% data_sub$amenities_clean[[i]] |
     "pool with pool hoist" %in% data_sub$amenities_clean[[i]]) {
    pool[i] <-  "yes"
  } else {
    pool[i] <-  "no"
  }
}
data_sub$pool <- pool
data_sub$pool <- factor(data_sub$pool, levels = c("yes", "no"))

# Create variable for hot_tub and add to data set
hot_tub <- vector()
for(i in 1:length(data_sub$amenities_clean)) {
  if("hot tub" %in% data_sub$amenities_clean[[i]]) {
    hot_tub[i] <-  "yes"
  } else {
    hot_tub[i] <-  "no"
  }
}
data_sub$hot_tub <- hot_tub
data_sub$hot_tub <- factor(data_sub$hot_tub, levels = c("yes", "no"))

# Create variable for hot_tub and add to data set
tv <- vector()
for(i in 1:length(data_sub$amenities_clean)) {
  if("tv" %in% data_sub$amenities_clean[[i]] |
     "cable tv" %in% data_sub$amenities_clean[[i]]) {
    tv[i] <-  "yes"
  } else {
    tv[i] <-  "no"
  }
}
data_sub$tv <- tv
data_sub$tv <- factor(data_sub$tv, levels = c("yes", "no"))

Clean host verification methods

For the variable host_verification the same applies as to amenities. We have applied the same cleaning method, first we cleaned and splitted the strings, whereafther we generated a vector with all unique amenities.

# Clean and split strings for host verification methods
# Returns a list with all unique values
clean_verficiations <- function(x) {
  subbed <- gsub("\\[|\\]", "", tolower(x))
  subbed_complete <- gsub("[']", "", subbed)
  splitted <- str_split(subbed_complete, ",")
  clean <- sapply(splitted, function(x) str_trim(x, side = "both"))
  return(clean)
}

# Clean host_verifications
data_sub$host_verifications_clean <- 
  sapply(data_sub$host_verifications, function(x) clean_verficiations(x))

# Generate list with all unique host verification methods
verifications_unique = c()
for(verifications in data_sub$host_verifications_clean) {
  for(element in verifications) {
    if(!(element %in% verifications_unique) & element != "") {
      verifications_unique <- append(verifications_unique, str_trim(element))
    }
  }
}

# Show result
verifications_unique
<<<<<<< HEAD
 [1] "email"                 "phone"                 "reviews"               "jumio"                 "offline_government_id"
 [6] "selfie"                "government_id"         "identity_manual"       "facebook"              "work_email"           
[11] "none"                  "google"                "manual_offline"        "manual_online"         "sent_id"              
[16] "kba"                   "weibo"                 "zhima_selfie"          "sesame"                "sesame_offline"       
=======
 [1] "email"                 "phone"                 "reviews"               "jumio"                 "offline_government_id" "selfie"                "government_id"         "identity_manual"       "facebook"             
[10] "work_email"            "none"                  "google"                "manual_offline"        "manual_online"         "sent_id"               "kba"                   "weibo"                 "zhima_selfie"         
[19] "sesame"                "sesame_offline"       
>>>>>>> fc0442fd76290b6483426e318740d6bc774d6ae0

Create variables based on information stored in host verifications

We created separate variables for the most common methods of verification, namely email, phone, facebook and government_id.

# Create variable for host email and add to data set
host_email <- vector()
for(i in 1:length(data_sub$host_verifications_clean)) {
  if("email" %in% data_sub$host_verifications_clean[[i]]) {
    host_email[i] <-  "yes"
  } else {
    host_email[i] <-  "no"
  }
}
data_sub$host_email <- host_email 
data_sub$host_email <- factor(data_sub$host_email, levels = c("yes", "no"))

# Create variable for phone and add to data set 
host_phone <- vector()
for(i in 1:length(data_sub$host_verifications_clean)) {
  if("phone" %in% data_sub$host_verifications_clean[[i]]) {
    host_phone[i] <-  "yes"
  } else {
    host_phone[i] <-  "no"
  }
}
data_sub$host_phone <- host_phone 
data_sub$host_phone <- factor(data_sub$host_phone, levels = c("yes", "no"))
 
# Create variable for host facebook and add to data set
host_facebook <- vector()
for(i in 1:length(data_sub$host_verifications_clean)) {
  if("facebook" %in% data_sub$host_verifications_clean[[i]]) {
    host_facebook[i] <-  "yes"
  } else {
    host_facebook[i] <-  "no"
  }
}
data_sub$host_facebook <- host_facebook 
data_sub$host_facebook <- 
  factor(data_sub$host_facebook, levels = c("yes", "no"))

# Create variable for government id 
host_government_id <- vector()
for(i in 1:length(data_sub$host_verifications_clean)) {
  if("government_id" %in% data_sub$host_verifications_clean[[i]]) {
    host_government_id[i] <-  "yes"
  } else {
    host_government_id[i] <-  "no"
  }
}
data_sub$host_government_id <- host_government_id 
data_sub$host_government_id <- 
  factor(data_sub$host_government_id, levels = c("yes", "no"))

Clean date variables

We used the variable host_since to create a new variable host_years_active, which contains information on the number of years a host has been active on the platform.

# Create new variable for active years host 
data_sub <- data_sub %>% 
  mutate(host_years_active = 
           as.double(as.Date("2019-12-07") - host_since) / 365)

Inspect availability variables

The variables availability_30, availability_60, availability_90 and availability_365 carry some of the same information. In order to inspect if we should include all variables in the data set, we plotted a correlation matrix. The plot below shows that all variables indicating the availability are strongly correlated. Therefore, we only include the variable availability_30 for further analysis.

# Plot correlation matrix
data_sub %>% select_if(is.numeric) %>% 
  select(availability_30, availability_60, availability_90, availability_365) %>% 
  cor() %>% corrplot()


# Remove other availability variables from data set
data_sub <- 
  data_sub %>% 
  select(-availability_60, -availability_90, -availability_365)

Check missing data

We have create a table to inspect with variables have missing cases and how many. The table shows the variables in the data set that contain missing values (in descending order). The table shows that the variable square_feet has \(19662\) missing cases, which is about \(98.19\%\). If we would deleted the missing cases, the data set will barely contain any data. Moreover, other methods for handling missing values like replacing NA-values with the mean or median would not be appropriate since the variables will be based on only \(1.81\%\) of the data. Therefore, square_feet is nog included in the final. The variable host_response_rate has \(9349\) missing cases, which is about \(46.69\%\). The variable host_neighbourhood has \(5972\), which is about \(29.82\%\). The variable cleaning_fee has \(3604\), which is about \(18.00\%\). The variables host_response_rate, host_neighbourhood and cleaning_fee do not have as many missing values as square_feet, however, the same reasoning applies. As a result, these variables are also excluded from the analyses.

# Count missing cases per variable
na_counter <- sapply(data_sub, function(x) sum(is.na(x)))
vars <- colnames(data_sub)

# Extract all variables with NA-values
na_values <- tibble(variables = vars, na_count = na_counter) 

# Check na count per variable
na_values %>%
  filter(na_count > 0) %>%
  arrange(desc(na_count))

Moreover, we have check how many cases contain missing values if the other values that have missing cases would be included in the ‘final’ data set. The table below shows that there are 206 cases which contain missing values, which is about \(1.03\%\) of the entire data set. Since this is a very small proportion it is not very likely that deleting these causes would have a large impact on the predictions. Therefore, we delete the cases with missing values.

# Compute incomplete rows
data_sub %>% 
  select(host_since, host_response_time, host_listings_count,
         host_identity_verified, beds, bedrooms, host_years_active, 
         bathrooms) %>% 
  complete.cases() %>% 
  summary(count())
   Mode   FALSE    TRUE 
logical     206   19819 
# Select variables for data set
variables_analysis <-   
  na_values %>% 
  filter(na_count <= 158) %>% 
  select(variables) %>% 
  pull(variables)

# Create final data set
data_semi_final <- data_sub %>% select(all_of(variables_analysis))
data_semi_final <- data_semi_final %>% 
  select(-c(amenities, amenities_clean, host_verifications,
            host_verifications_clean, host_since))
data_final <- data_semi_final[complete.cases(data_semi_final), ]

Create train-test split

For further analysis the data is split into a train-test set.

# Create a train-split sets
seed_x <-  123
set.seed(seed_x)
data_split <- initial_split(data_final, prop = 0.7)
data_train <- training(data_split)
data_test <- testing(data_split)

Inspecting the predicted variable

In order to prevent data leakages we only inspect the predicted variable price in the training set. In order to inspect price we have created a distribution plot. The plot shows that the data set contains some outliers and that the distribution is rightly skewed. Both the outliers and the skeweness make the data less interpretable and this could have an influence on performance of the models.

# Plot distribution price
ggplot(data = data_train , aes(price)) +
  geom_histogram(col="black",
                 breaks=seq(0, max(data_train$price), by=75),
                 aes(fill=..count..)) +
  labs(title="Histogram for Price", x="Price", y="Count") +
  scale_fill_gradient("Count", low="green", high="red")

In order to prevent this potential problems we have created a new distribution plot with a log transformed variable price. The plot shows that the distribution is less skewed and does not contain any large outliers. Resulting, the data that is more interpretable. Therefore, log transforming we will use the log transformed price for our models.

# Plot distribution price
ggplot(data = data_train , aes(log(price + 1))) +
  geom_histogram(col="black",
                 aes(fill=..count..)) +
  labs(title="Histogram for Ln Price", x="Ln Price", y="Count") +
  scale_fill_gradient("Count", low="green", high="red")

# Log transform the price in for both training and test set
data_final$price <- log(data_final$price + 1)

# Resplit the data using the same seed 
set.seed(seed_x)
data_split <- initial_split(data_final, prop = 0.7)
data_train <- training(data_split)
data_test <- testing(data_split)

K-fold cross validation

Moreover, we have generated 10-fold cross validation sets.

# Generate 10-fold CV sets
set.seed(321)
data_folds <- vfold_cv(data_train, v = 10)
data_folds
#  10-fold cross-validation 
<<<<<<< HEAD ======= >>>>>>> fc0442fd76290b6483426e318740d6bc774d6ae0

Remove data frames to avoid leakages and errors

rm(data)
rm(data_sub)
rm(data_semi_final)
rm(na_values)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIFNldHVwIG5vdGVib29rDQoNClRoZSBmb2xsb3dpbmcgbGlicmFyaWVzIGFyZSB1c2VkIGluIGZvciBpbiB0aGlzIG5vdGVib29rOg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFfQ0KIyBMb2FkIGxpYnJhcmllcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHRpZHltb2RlbHMpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShnbG1uZXQpDQpsaWJyYXJ5KGxlYXBzKQ0KbGlicmFyeShuYW5pYXIpDQpsaWJyYXJ5KHNraW1yKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoY29ycnBsb3QpDQpgYGANCg0KIyBMb2FkIGRhdGEgbGlzdGluZ3MNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0NCiMgUmVhZCBjc3Ygd2l0aCBsaXN0aW5nIGluZm9ybWF0aW9uDQpkYXRhIDwtIHJlYWRfY3N2KGd6ZmlsZSgibGlzdGluZ3MuY3N2Lmd6IikpDQpgYGANCg0KIyBTZWxlY3QgdmFyaWFibGVzIG9mIGludGVyZXN0DQpUaGUgZ29hbCBvZiB0aGUgYXNzaWdubWVudCBpcyB0byBidWlsZCBhIG1vZGVsIHRoYXQgcHJlZGljdHMgdGhlIHByaWNlcyBvZiBsaXN0aW5ncyBvbiBBaXJCbkIgaW4gQW1zdGVyZGFtLiBUaGUgb3V0Y29tZXMgb2YgdGhlIG1vZGVsIHdpbGwgYmUgdXNlZCBmb3Igc3VnZ2VzdGlvbnMgdG8gdGhlIG5ldyBob3N0cyBhYm91dCB0aGUgYXZlcmFnZSBwbGF0Zm9ybSBwcmljZSBmb3Igc2ltaWxhciBsaXN0aW5ncy4gVGhlbiBob3N0cyBjYW4gY2hvb3NlIHdoZXRoZXIgdGhleSB3YW50IHRvIHVzZSB0aGUgcmVjb21tZW5kYXRpb24gdG8gc2V0IHRoZWlyIHByaWNlcyBhY2NvcmRpbmdseSBpbiBvcmRlciB0byBiZSBjb21wZXRpdGl2ZSBhbmQgZ2FpbiBhdHRlbnRpb24gZnJvbSB0aGUgZ3Vlc3RzIHNpbmNlIHRoZSBiZWdpbm5pbmcuIEFsbCB2YXJpYWJsZXMgaW5jbHVkaW5nIGluZm9ybWF0aW9uIG9uIHRoZSByZXZpZXdzIGdpdmUgaW5mb3JtYXRpb24gYWJvdXQgYSBsaXN0aW5nIGFmdGVyIGl0IGhhcyBiZWVuIHB1Ymxpc2hlZC4gVGhlcmVmb3JlLCB0aGlzIHZhcmlhYmxlcyBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBkYXRhIHNldC4gTW9yZW92ZXIsIHRoZSB2YXJpYWJsZXMgaW5jbHVkaW5nIGEgZGVzY3JpcHRpb24gYW5kIHN1bW1hcnkgYWJvdXQgdGhlIGxpc3RpbmcgY2FuIGJlIGFuYWx5emVkIHVzaW5nIE5MUCAoZS5nLiBzZW50aW1lbnQgYW5hbHlzaXMpLiBIb3dldmVyLCB0aGlzIGlzIGJleW9uZCB0aGUgc2NvcGUgb2YgdGhlIGFzc2lnbm1lbnQuIFRoZXJlZm9yZSwgdGhlc2UgdmFyaWFibGVzIGFyZSBleGNsdWRlZCBmcm9tIHRoZSBtb2RlbC4gVGhlIHZhcmlhYmxlcyBiZWxvdyBhcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGEgc2V0IGZvciBmdXJ0aGVyIGFuYWx5c2lzIGFuZCBjbGVhbmluZy4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFfQ0KIyBHZW5lcmF0ZSBzdWJzZXQgd2l0aCB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCmRhdGFfc3ViIDwtIGRhdGEgJT4lDQogIHNlbGVjdChpZCwgcHJpY2UsIHByb3BlcnR5X3R5cGUsIHJvb21fdHlwZSwgYWNjb21tb2RhdGVzLCBiYXRocm9vbXMsIGJlZHJvb21zLA0KICAgICAgICAgYmVkcywgYmVkX3R5cGUsIGFtZW5pdGllcywgaG9zdF9zaW5jZSwgaG9zdF9yZXNwb25zZV90aW1lLA0KICAgICAgICAgaG9zdF9yZXNwb25zZV9yYXRlLCBob3N0X25laWdoYm91cmhvb2QsIGhvc3RfbGlzdGluZ3NfY291bnQsIA0KICAgICAgICAgaG9zdF92ZXJpZmljYXRpb25zLCBob3N0X2lkZW50aXR5X3ZlcmlmaWVkLCBuZWlnaGJvdXJob29kX2NsZWFuc2VkLA0KICAgICAgICAgc3F1YXJlX2ZlZXQsIGNsZWFuaW5nX2ZlZSwgZ3Vlc3RzX2luY2x1ZGVkLCBleHRyYV9wZW9wbGUsIA0KICAgICAgICAgbWluaW11bV9uaWdodHMsIG1heGltdW1fbmlnaHRzLCBhdmFpbGFiaWxpdHlfMzAsIGF2YWlsYWJpbGl0eV82MCwNCiAgICAgICAgIGF2YWlsYWJpbGl0eV85MCwgYXZhaWxhYmlsaXR5XzM2NSwgaW5zdGFudF9ib29rYWJsZSwgDQogICAgICAgICBjYW5jZWxsYXRpb25fcG9saWN5LCByZXF1aXJlX2d1ZXN0X3Byb2ZpbGVfcGljdHVyZSwNCiAgICAgICAgIHJlcXVpcmVfZ3Vlc3RfcGhvbmVfdmVyaWZpY2F0aW9uLCBjYWxjdWxhdGVkX2hvc3RfbGlzdGluZ3NfY291bnQsDQogICAgICAgICBjYWxjdWxhdGVkX2hvc3RfbGlzdGluZ3NfY291bnRfZW50aXJlX2hvbWVzLCANCiAgICAgICAgIGNhbGN1bGF0ZWRfaG9zdF9saXN0aW5nc19jb3VudF9wcml2YXRlX3Jvb21zLA0KICAgICAgICAgY2FsY3VsYXRlZF9ob3N0X2xpc3RpbmdzX2NvdW50X3NoYXJlZF9yb29tcykNCmBgYA0KDQpgYGB7cn0NCiMgSW5zcGVjdCBkYXRhDQpoZWFkKGRhdGFfc3ViKQ0KYGBgDQoNCmBgYHtyfQ0KIyBJbnNwZWN0IGRhdGENCnNraW0oZGF0YV9zdWIpICU+JSBrbml0X3ByaW50KCkNCmBgYA0KDQojIERhdGEgY2xlYW5pbmcNCg0KIyMgQmFzaWMgY2xlYW5pbmcNCg0KRmlyc3QsIHdlIGNvbnZlcnRlZCBhbGwgY2F0ZWdvcmljYWwgZW4gbG9naWNhbCB2YXJpYWJsZXMsIHRoYXQgZGlkIG5vdCBuZWVkIGFueSBmdXJ0aGVyIGNsZWFuaW5nLCB0byB0eXBlIGZhY3RvcnMuDQpgYGB7ciBDb252ZXJ0aW5nIHZlY3RvcnN9DQojIENvbnZlcnQgY29sdW1ucyB0byBmYWN0b3JzIA0KZGF0YV9zdWIkcHJvcGVydHlfdHlwZSA8LSBmYWN0b3IoZGF0YV9zdWIkcHJvcGVydHlfdHlwZSAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGRhdGFfc3ViJHByb3BlcnR5X3R5cGUpKQ0KZGF0YV9zdWIkcm9vbV90eXBlIDwtIGZhY3RvcihkYXRhX3N1YiRyb29tX3R5cGUgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGRhdGFfc3ViJHJvb21fdHlwZSkpDQpkYXRhX3N1YiRiZWRfdHlwZSA8LSBmYWN0b3IoZGF0YV9zdWIkYmVkX3R5cGUgLCANCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGRhdGFfc3ViJGJlZF90eXBlKSkNCmRhdGFfc3ViJGhvc3RfcmVzcG9uc2VfdGltZSA8LSBmYWN0b3IoZGF0YV9zdWIkIGhvc3RfcmVzcG9uc2VfdGltZSwgDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShkYXRhX3N1YiRob3N0X3Jlc3BvbnNlX3RpbWUpKQ0KZGF0YV9zdWIkaG9zdF9uZWlnaGJvdXJob29kIDwtIGZhY3RvcihkYXRhX3N1YiRob3N0X25laWdoYm91cmhvb2QsIA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZGF0YV9zdWIkaG9zdF9uZWlnaGJvdXJob29kKSkNCmRhdGFfc3ViJG5laWdoYm91cmhvb2RfY2xlYW5zZWQgPC0gZmFjdG9yKGRhdGFfc3ViJG5laWdoYm91cmhvb2RfY2xlYW5zZWQsIA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZGF0YV9zdWIkbmVpZ2hib3VyaG9vZF9jbGVhbnNlZCkpDQpkYXRhX3N1YiRjYW5jZWxsYXRpb25fcG9saWN5IDwtIGZhY3RvcihkYXRhX3N1YiRjYW5jZWxsYXRpb25fcG9saWN5ICwgDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShkYXRhX3N1YiRjYW5jZWxsYXRpb25fcG9saWN5KSkNCg0KIyBDb252ZXJ0IGxvZ2ljYWwgdmFyaWFibGVzIHRvIGZhY3RvcnMNCmRhdGFfc3ViJGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQgPC0gZmFjdG9yKGRhdGFfc3ViJGhvc3RfaWRlbnRpdHlfdmVyaWZpZWQpDQpkYXRhX3N1YiRpbnN0YW50X2Jvb2thYmxlIDwtIGZhY3RvcihkYXRhX3N1YiRpbnN0YW50X2Jvb2thYmxlKQ0KZGF0YV9zdWIkcmVxdWlyZV9ndWVzdF9wcm9maWxlX3BpY3R1cmUgPC0gDQogIGZhY3RvcihkYXRhX3N1YiRyZXF1aXJlX2d1ZXN0X3Byb2ZpbGVfcGljdHVyZSkNCmRhdGFfc3ViJHJlcXVpcmVfZ3Vlc3RfcGhvbmVfdmVyaWZpY2F0aW9uIDwtIA0KICBmYWN0b3IoZGF0YV9zdWIkcmVxdWlyZV9ndWVzdF9waG9uZV92ZXJpZmljYXRpb24pDQpgYGANCg0KU2Vjb25kLCBzb21lIG9mIHRoZSB2YXJpYWJsZXMgY29udGFpbiBudW1lcmljIHZhcmlhYmxlcywgaG93ZXZlciwgdGhleSBhcmUgc3RvcmVkIGluIGEgc3RyaW5nIGNvbnRhaW5pbmcgYSBkb2xsYXIgb3IgcGVyY2VudGFnZSBzaWduLiBUaGUgc2lnbnMgd2UgcmVtb3ZlZCBmcm9tIHRoZSBzdHJpbmdzIGFuZCB0aGUgcmVtYWluaW5nIG51bWJlciBjb252ZXJ0ZWQgdG8gbnVtZXJpYyB2YXJpYWJsZXMuDQpgYGB7ciBDb252ZXJ0IH0NCiMgUmVtb3ZlICQgc2lnbiBmcm9tIGNvbHVtbnMgY29udGFpbmluZyBwcmljZXMgYW5kIGNvbnZlcnQgdG8gZG91Ymxlcw0KZGF0YV9zdWIkcHJpY2UgPC0gYXMuZG91YmxlKGdzdWIoIlssJF0iLCAiIiwgZGF0YV9zdWIkcHJpY2UpKQ0KZGF0YV9zdWIkY2xlYW5pbmdfZmVlIDwtIGFzLmRvdWJsZShnc3ViKCJbLCRdIiwgIiIsIGRhdGFfc3ViJGNsZWFuaW5nX2ZlZSkpDQpkYXRhX3N1YiRleHRyYV9wZW9wbGUgPC0gYXMuZG91YmxlKGdzdWIoIlssJF0iLCAiIiwgZGF0YV9zdWIkZXh0cmFfcGVvcGxlKSkNCg0KIyBSZXBsYWNlICJOL0EiIHZhbHVlcywgcmVtb3ZlICUgYW5kIGNvbnZlcnQgdG8gcGVyY2VudGFnZSANCmRhdGFfc3ViJGhvc3RfcmVzcG9uc2VfcmF0ZSA8LSBuYV9pZihkYXRhX3N1YiRob3N0X3Jlc3BvbnNlX3JhdGUsICJOL0EiKQ0KZGF0YV9zdWIkaG9zdF9yZXNwb25zZV9yYXRlIDwtIA0KICBhcy5kb3VibGUoZ3N1YigiWyVdIiwgIiIsIGRhdGFfc3ViJGhvc3RfcmVzcG9uc2VfcmF0ZSkpIC8gMTAwDQpgYGANCg0KIyMgQ2xlYW4gYW1lbml0aWVzIA0KDQpUaGUgdmFyaWFibGUgKmFtZW5pdGllcyogY29udGFpbnMgYWxsIHRoZSBhbWVuaXRpZXMgb2YgdGhlIGxpc3RpbmcuIEhvd2V2ZXIsIHRoaXMgd2FzIHN0b3JlZCBpbiBvbmUgbGFyZ2Ugc3RyaW5nIGFuZCB0aGUgZWxlbWVudHMgY291bGQgbm90IGJlIGFjY2VzcyBzZXBhcmF0ZWx5LiBUaGVyZWZvcmUsIHdlIGNsZWFuZWQgdGhlIHN0cmluZywgc3BpdHRlZCBpdCBzbyB3ZSBoYWQgYSBsaXN0IGNvbnRhaW5pbmcgdGhlIHNlcGFyYXRlZCBlbGVtZW50cy4gRnVydGhlcm1vcmUsIHdlIGV4dHJhY3RlZCBhbGwgdW5pcXVlIGFtZW5pdGllcyBhbmQgc3RvcmVkIHRoZXNlIGluIGEgdmVjdG9yLiANCmBgYHtyIEdlbmVyYXRlIGFsbCB1bmlxdWUgYW1lbml0aWVzfQ0KIyBDbGVhbiBhbmQgc3BsaXQgc3RyaW5ncyBmb3IgYW1lbml0aWVzDQojIFJldHVybnMgYSBsaXN0IHdpdGggYWxsIHVuaXF1ZSB2YWx1ZXMNCmNsZWFuX2FtZW5pdGllcyA8LSBmdW5jdGlvbih4KSB7DQogIHN1YmJlZCA8LSBnc3ViKCdbe31cIl0nLCAiIiwgdG9sb3dlcih4KSkNCiAgc3BsaXR0ZWQgPC0gc3RyX3NwbGl0KHN1YmJlZCwgIiwiKQ0KICBjbGVhbiA8LSBzYXBwbHkoc3BsaXR0ZWQsIGZ1bmN0aW9uKHgpIHN0cl90cmltKHgsIHNpZGUgPSAiYm90aCIpKQ0KICByZXR1cm4oY2xlYW4pDQp9DQoNCiMgQ2xlYW4gYW1lbml0aWVzDQpkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW4gPC0gDQogIHNhcHBseShkYXRhX3N1YiRhbWVuaXRpZXMsIGZ1bmN0aW9uKHgpIGNsZWFuX2FtZW5pdGllcyh4KSkNCg0KIyBDcmVhdGUgdmVjdG9yIHdpdGggYWxsIHVuaXF1ZSBhbWVuaXRpZXMNCmFtZW5pdGllc191bmlxdWUgPSBjKCkNCmZvcihhbWVuaXRpZXMgaW4gZGF0YV9zdWIkYW1lbml0aWVzX2NsZWFuKSB7DQogIGZvcihlbGVtZW50IGluIGFtZW5pdGllcykgew0KICAgIGlmKCEoZWxlbWVudCAlaW4lIGFtZW5pdGllc191bmlxdWUpICYgZWxlbWVudCAhPSAiIikgew0KICAgICAgYW1lbml0aWVzX3VuaXF1ZSA8LSBhcHBlbmQoYW1lbml0aWVzX3VuaXF1ZSwgc3RyX3RyaW0oZWxlbWVudCkpDQogICAgfQ0KICB9DQp9DQoNCiMgU2hvdyByZXN1bHQNCmFtZW5pdGllc191bmlxdWUNCmBgYA0KDQojIyMgQ3JlYXRlIG5ldyB2YXJpYWJsZXMgYmFzZWQgaW5mb3JtYXRpb24gc3RvcmVkIGluIGFtZW5pdGllcw0KDQpXaXRoIHRoZSB2ZWN0b3Igb2YgYWxsIHVuaXF1ZSBhbWVuaXRpZXMgd2UgY291bGQgY3JlYXRlIHZhcmlhYmxlcyBmb3IgYWxsIHRoZSBzZXBhcmF0ZWQgdmFyaWFibGVzLiBIb3dldmVyLCBzaW5jZSB0aGVyZSBhcmUgMTMwIHVzYWJsZSBhbWVuaXRpZXMgaXQgc2VlbWVkIGJleW9uZCB0aGUgc2NvcGUgb2YgdGhlIGFzc2lnbm1lbnQuIE1vcmVvdmVyLCBzb21lIG9mIHRoZSBhbWVuaXRpZXMgY29udGFpbiBpbmZvcm1hdGlvbiB0aGF0IGlzIGFsc28gZ2l2ZW4gYnkgb3RoZXIgdmFyaWFibGVzIG9yIGFib3V0IG90aGVyIGFtZW5pdGllcy4gRm9yIGV4YW1wbGUgYSBwcml2YXRlIGJhdGhyb29tIGNvdWxkIGFsc28gYmUgYSBzdHJvbmcgaW5kaWNhdG9yIHRoYXQgdGhlIGxpc3RpbmcgaXMgYW4gZW50aXJlIGhvdXNlL2FwYXJ0bWVudC4gQWxzbywgc2hhbXBvbyBvciBzaG93ZXIgZ2VsIGNvdWxkIGJlIHN0cm9uZyBpbmRpY2F0b3JzIGZvciB0aGUgcHJlc2VuY2Ugb2YgYSBiYXRocm9vbS4gRnVydGhlcm1vcmUsIHNvbWUgYXJlIGFtZW5pdGllcyBhcmUgdmVyeSBzcGVjaWZpYyBhbmQgYXBwbHkgb25seSB0byBhIGZldyBvciBvbmUgaG91c2UuIEhvd2V2ZXIsIHdlIGNyZWF0ZWQgdmFyaWFibGVzIHNvbWUgb2YgdGhlIGFtZW5pdGllcyB3ZSB0aGluayBjb3VsZCBoYXZlIGFuIGluZmx1ZW5jZSBvbiB0aGUgcHJpY2Ugb2YgYSBsaXN0aW5nLiBXZSBjcmVhdGVkIHZhcmlhYmxlcyBmb3IgKndpZmkqLCAqcG9vbCosICpob3RfdHViKiBhbmQgKnR2Ki4gDQpgYGB7ciBDcmVhdGUgbmV3IHZhcmlhYmxlcyBmb3IgYW1lbml0aWVzfQ0KIyBDcmVhdGUgdmFyaWFibGUgZm9yIFdJRkkgYW5kIGFkZCB0byBkYXRhIHNldA0Kd2lmaSA8LSB2ZWN0b3IoKQ0KZm9yKGkgaW4gMTpsZW5ndGgoZGF0YV9zdWIkYW1lbml0aWVzX2NsZWFuKSkgew0KICBpZigid2lmaSIgJWluJSBkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW5bW2ldXSB8IA0KICAgICAiaW50ZXJuZXQiICVpbiUgZGF0YV9zdWIkYW1lbml0aWVzX2NsZWFuW1tpXV0pIHsNCiAgICB3aWZpW2ldIDwtICAieWVzIg0KICB9IGVsc2Ugew0KICAgIHdpZmlbaV0gPC0gICJubyINCiAgfQ0KfQ0KZGF0YV9zdWIkd2lmaSA8LSB3aWZpDQpkYXRhX3N1YiR3aWZpIDwtIGZhY3RvcihkYXRhX3N1YiR3aWZpLCBsZXZlbHMgPSBjKCJ5ZXMiLCAibm8iKSkNCg0KIyBDcmVhdGUgdmFyaWFibGUgZm9yIHBvb2wgYW5kIGFkZCB0byBkYXRhIHNldA0KcG9vbCA8LSB2ZWN0b3IoKQ0KZm9yKGkgaW4gMTpsZW5ndGgoZGF0YV9zdWIkYW1lbml0aWVzX2NsZWFuKSkgew0KICBpZigicG9vbCIgJWluJSBkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW5bW2ldXSB8DQogICAgICJwb29sIHdpdGggcG9vbCBob2lzdCIgJWluJSBkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW5bW2ldXSkgew0KICAgIHBvb2xbaV0gPC0gICJ5ZXMiDQogIH0gZWxzZSB7DQogICAgcG9vbFtpXSA8LSAgIm5vIg0KICB9DQp9DQpkYXRhX3N1YiRwb29sIDwtIHBvb2wNCmRhdGFfc3ViJHBvb2wgPC0gZmFjdG9yKGRhdGFfc3ViJHBvb2wsIGxldmVscyA9IGMoInllcyIsICJubyIpKQ0KDQojIENyZWF0ZSB2YXJpYWJsZSBmb3IgaG90X3R1YiBhbmQgYWRkIHRvIGRhdGEgc2V0DQpob3RfdHViIDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOmxlbmd0aChkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW4pKSB7DQogIGlmKCJob3QgdHViIiAlaW4lIGRhdGFfc3ViJGFtZW5pdGllc19jbGVhbltbaV1dKSB7DQogICAgaG90X3R1YltpXSA8LSAgInllcyINCiAgfSBlbHNlIHsNCiAgICBob3RfdHViW2ldIDwtICAibm8iDQogIH0NCn0NCmRhdGFfc3ViJGhvdF90dWIgPC0gaG90X3R1Yg0KZGF0YV9zdWIkaG90X3R1YiA8LSBmYWN0b3IoZGF0YV9zdWIkaG90X3R1YiwgbGV2ZWxzID0gYygieWVzIiwgIm5vIikpDQoNCiMgQ3JlYXRlIHZhcmlhYmxlIGZvciBob3RfdHViIGFuZCBhZGQgdG8gZGF0YSBzZXQNCnR2IDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOmxlbmd0aChkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW4pKSB7DQogIGlmKCJ0diIgJWluJSBkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW5bW2ldXSB8DQogICAgICJjYWJsZSB0diIgJWluJSBkYXRhX3N1YiRhbWVuaXRpZXNfY2xlYW5bW2ldXSkgew0KICAgIHR2W2ldIDwtICAieWVzIg0KICB9IGVsc2Ugew0KICAgIHR2W2ldIDwtICAibm8iDQogIH0NCn0NCmRhdGFfc3ViJHR2IDwtIHR2DQpkYXRhX3N1YiR0diA8LSBmYWN0b3IoZGF0YV9zdWIkdHYsIGxldmVscyA9IGMoInllcyIsICJubyIpKQ0KYGBgDQoNCiMjIENsZWFuIGhvc3QgdmVyaWZpY2F0aW9uIG1ldGhvZHMNCg0KRm9yIHRoZSB2YXJpYWJsZSAqaG9zdF92ZXJpZmljYXRpb24qIHRoZSBzYW1lIGFwcGxpZXMgYXMgdG8gKmFtZW5pdGllcyouIFdlIGhhdmUgYXBwbGllZCB0aGUgc2FtZSBjbGVhbmluZyBtZXRob2QsIGZpcnN0IHdlIGNsZWFuZWQgYW5kIHNwbGl0dGVkIHRoZSBzdHJpbmdzLCB3aGVyZWFmdGhlciB3ZSBnZW5lcmF0ZWQgYSB2ZWN0b3Igd2l0aCBhbGwgdW5pcXVlIGFtZW5pdGllcy4NCmBgYHtyIEdlbmVyYXRlIHVuaXF1ZSBob3N0IHZlcmlmaWNhdGlvbiBtZXRob2RzfQ0KIyBDbGVhbiBhbmQgc3BsaXQgc3RyaW5ncyBmb3IgaG9zdCB2ZXJpZmljYXRpb24gbWV0aG9kcw0KIyBSZXR1cm5zIGEgbGlzdCB3aXRoIGFsbCB1bmlxdWUgdmFsdWVzDQpjbGVhbl92ZXJmaWNpYXRpb25zIDwtIGZ1bmN0aW9uKHgpIHsNCiAgc3ViYmVkIDwtIGdzdWIoIlxcW3xcXF0iLCAiIiwgdG9sb3dlcih4KSkNCiAgc3ViYmVkX2NvbXBsZXRlIDwtIGdzdWIoIlsnXSIsICIiLCBzdWJiZWQpDQogIHNwbGl0dGVkIDwtIHN0cl9zcGxpdChzdWJiZWRfY29tcGxldGUsICIsIikNCiAgY2xlYW4gPC0gc2FwcGx5KHNwbGl0dGVkLCBmdW5jdGlvbih4KSBzdHJfdHJpbSh4LCBzaWRlID0gImJvdGgiKSkNCiAgcmV0dXJuKGNsZWFuKQ0KfQ0KDQojIENsZWFuIGhvc3RfdmVyaWZpY2F0aW9ucw0KZGF0YV9zdWIkaG9zdF92ZXJpZmljYXRpb25zX2NsZWFuIDwtIA0KICBzYXBwbHkoZGF0YV9zdWIkaG9zdF92ZXJpZmljYXRpb25zLCBmdW5jdGlvbih4KSBjbGVhbl92ZXJmaWNpYXRpb25zKHgpKQ0KDQojIEdlbmVyYXRlIGxpc3Qgd2l0aCBhbGwgdW5pcXVlIGhvc3QgdmVyaWZpY2F0aW9uIG1ldGhvZHMNCnZlcmlmaWNhdGlvbnNfdW5pcXVlID0gYygpDQpmb3IodmVyaWZpY2F0aW9ucyBpbiBkYXRhX3N1YiRob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW4pIHsNCiAgZm9yKGVsZW1lbnQgaW4gdmVyaWZpY2F0aW9ucykgew0KICAgIGlmKCEoZWxlbWVudCAlaW4lIHZlcmlmaWNhdGlvbnNfdW5pcXVlKSAmIGVsZW1lbnQgIT0gIiIpIHsNCiAgICAgIHZlcmlmaWNhdGlvbnNfdW5pcXVlIDwtIGFwcGVuZCh2ZXJpZmljYXRpb25zX3VuaXF1ZSwgc3RyX3RyaW0oZWxlbWVudCkpDQogICAgfQ0KICB9DQp9DQoNCiMgU2hvdyByZXN1bHQNCnZlcmlmaWNhdGlvbnNfdW5pcXVlDQpgYGANCg0KIyMjIENyZWF0ZSB2YXJpYWJsZXMgYmFzZWQgb24gaW5mb3JtYXRpb24gc3RvcmVkIGluIGhvc3QgdmVyaWZpY2F0aW9ucw0KDQpXZSBjcmVhdGVkIHNlcGFyYXRlIHZhcmlhYmxlcyBmb3IgdGhlIG1vc3QgY29tbW9uIG1ldGhvZHMgb2YgdmVyaWZpY2F0aW9uLCBuYW1lbHkgKmVtYWlsKiwgKnBob25lKiwgKmZhY2Vib29rKiBhbmQgKmdvdmVybm1lbnRfaWQqLiANCmBgYHtyIENyZWF0ZSBuZXcgdmFyaWFibGVzIGZvciBob3N0IHZlcmlmaWNhdGlvbiBtZXRob2R9DQojIENyZWF0ZSB2YXJpYWJsZSBmb3IgaG9zdCBlbWFpbCBhbmQgYWRkIHRvIGRhdGEgc2V0DQpob3N0X2VtYWlsIDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOmxlbmd0aChkYXRhX3N1YiRob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW4pKSB7DQogIGlmKCJlbWFpbCIgJWluJSBkYXRhX3N1YiRob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW5bW2ldXSkgew0KICAgIGhvc3RfZW1haWxbaV0gPC0gICJ5ZXMiDQogIH0gZWxzZSB7DQogICAgaG9zdF9lbWFpbFtpXSA8LSAgIm5vIg0KICB9DQp9DQpkYXRhX3N1YiRob3N0X2VtYWlsIDwtIGhvc3RfZW1haWwgDQpkYXRhX3N1YiRob3N0X2VtYWlsIDwtIGZhY3RvcihkYXRhX3N1YiRob3N0X2VtYWlsLCBsZXZlbHMgPSBjKCJ5ZXMiLCAibm8iKSkNCg0KIyBDcmVhdGUgdmFyaWFibGUgZm9yIHBob25lIGFuZCBhZGQgdG8gZGF0YSBzZXQgDQpob3N0X3Bob25lIDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOmxlbmd0aChkYXRhX3N1YiRob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW4pKSB7DQogIGlmKCJwaG9uZSIgJWluJSBkYXRhX3N1YiRob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW5bW2ldXSkgew0KICAgIGhvc3RfcGhvbmVbaV0gPC0gICJ5ZXMiDQogIH0gZWxzZSB7DQogICAgaG9zdF9waG9uZVtpXSA8LSAgIm5vIg0KICB9DQp9DQpkYXRhX3N1YiRob3N0X3Bob25lIDwtIGhvc3RfcGhvbmUgDQpkYXRhX3N1YiRob3N0X3Bob25lIDwtIGZhY3RvcihkYXRhX3N1YiRob3N0X3Bob25lLCBsZXZlbHMgPSBjKCJ5ZXMiLCAibm8iKSkNCiANCiMgQ3JlYXRlIHZhcmlhYmxlIGZvciBob3N0IGZhY2Vib29rIGFuZCBhZGQgdG8gZGF0YSBzZXQNCmhvc3RfZmFjZWJvb2sgPC0gdmVjdG9yKCkNCmZvcihpIGluIDE6bGVuZ3RoKGRhdGFfc3ViJGhvc3RfdmVyaWZpY2F0aW9uc19jbGVhbikpIHsNCiAgaWYoImZhY2Vib29rIiAlaW4lIGRhdGFfc3ViJGhvc3RfdmVyaWZpY2F0aW9uc19jbGVhbltbaV1dKSB7DQogICAgaG9zdF9mYWNlYm9va1tpXSA8LSAgInllcyINCiAgfSBlbHNlIHsNCiAgICBob3N0X2ZhY2Vib29rW2ldIDwtICAibm8iDQogIH0NCn0NCmRhdGFfc3ViJGhvc3RfZmFjZWJvb2sgPC0gaG9zdF9mYWNlYm9vayANCmRhdGFfc3ViJGhvc3RfZmFjZWJvb2sgPC0gDQogIGZhY3RvcihkYXRhX3N1YiRob3N0X2ZhY2Vib29rLCBsZXZlbHMgPSBjKCJ5ZXMiLCAibm8iKSkNCg0KIyBDcmVhdGUgdmFyaWFibGUgZm9yIGdvdmVybm1lbnQgaWQgDQpob3N0X2dvdmVybm1lbnRfaWQgPC0gdmVjdG9yKCkNCmZvcihpIGluIDE6bGVuZ3RoKGRhdGFfc3ViJGhvc3RfdmVyaWZpY2F0aW9uc19jbGVhbikpIHsNCiAgaWYoImdvdmVybm1lbnRfaWQiICVpbiUgZGF0YV9zdWIkaG9zdF92ZXJpZmljYXRpb25zX2NsZWFuW1tpXV0pIHsNCiAgICBob3N0X2dvdmVybm1lbnRfaWRbaV0gPC0gICJ5ZXMiDQogIH0gZWxzZSB7DQogICAgaG9zdF9nb3Zlcm5tZW50X2lkW2ldIDwtICAibm8iDQogIH0NCn0NCmRhdGFfc3ViJGhvc3RfZ292ZXJubWVudF9pZCA8LSBob3N0X2dvdmVybm1lbnRfaWQgDQpkYXRhX3N1YiRob3N0X2dvdmVybm1lbnRfaWQgPC0gDQogIGZhY3RvcihkYXRhX3N1YiRob3N0X2dvdmVybm1lbnRfaWQsIGxldmVscyA9IGMoInllcyIsICJubyIpKQ0KYGBgDQoNCiMjIENsZWFuIGRhdGUgdmFyaWFibGVzDQoNCldlIHVzZWQgdGhlIHZhcmlhYmxlICpob3N0X3NpbmNlKiB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgKmhvc3RfeWVhcnNfYWN0aXZlKiwgd2hpY2ggY29udGFpbnMgaW5mb3JtYXRpb24gb24gdGhlIG51bWJlciBvZiB5ZWFycyBhIGhvc3QgaGFzIGJlZW4gYWN0aXZlIG9uIHRoZSBwbGF0Zm9ybS4gDQpgYGB7ciBDcmVhdGUgbmV3IHZhcmlhYmxlfQ0KIyBDcmVhdGUgbmV3IHZhcmlhYmxlIGZvciBhY3RpdmUgeWVhcnMgaG9zdCANCmRhdGFfc3ViIDwtIGRhdGFfc3ViICU+JSANCiAgbXV0YXRlKGhvc3RfeWVhcnNfYWN0aXZlID0gDQogICAgICAgICAgIGFzLmRvdWJsZShhcy5EYXRlKCIyMDE5LTEyLTA3IikgLSBob3N0X3NpbmNlKSAvIDM2NSkNCmBgYA0KDQojIyBJbnNwZWN0IGF2YWlsYWJpbGl0eSB2YXJpYWJsZXMNCg0KVGhlIHZhcmlhYmxlcyAqYXZhaWxhYmlsaXR5XzMwKiwgKmF2YWlsYWJpbGl0eV82MCosICphdmFpbGFiaWxpdHlfOTAqIGFuZCAqYXZhaWxhYmlsaXR5XzM2NSogY2Fycnkgc29tZSBvZiB0aGUgc2FtZSBpbmZvcm1hdGlvbi4gSW4gb3JkZXIgdG8gaW5zcGVjdCBpZiB3ZSBzaG91bGQgaW5jbHVkZSBhbGwgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCwgd2UgcGxvdHRlZCBhIGNvcnJlbGF0aW9uIG1hdHJpeC4gVGhlIHBsb3QgYmVsb3cgc2hvd3MgdGhhdCBhbGwgdmFyaWFibGVzIGluZGljYXRpbmcgdGhlIGF2YWlsYWJpbGl0eSBhcmUgc3Ryb25nbHkgY29ycmVsYXRlZC4gVGhlcmVmb3JlLCB3ZSBvbmx5IGluY2x1ZGUgdGhlIHZhcmlhYmxlICphdmFpbGFiaWxpdHlfMzAqIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiANCmBgYHtyfQ0KIyBQbG90IGNvcnJlbGF0aW9uIG1hdHJpeA0KZGF0YV9zdWIgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUgDQogIHNlbGVjdChhdmFpbGFiaWxpdHlfMzAsIGF2YWlsYWJpbGl0eV82MCwgYXZhaWxhYmlsaXR5XzkwLCBhdmFpbGFiaWxpdHlfMzY1KSAlPiUgDQogIGNvcigpICU+JSBjb3JycGxvdCgpDQoNCiMgUmVtb3ZlIG90aGVyIGF2YWlsYWJpbGl0eSB2YXJpYWJsZXMgZnJvbSBkYXRhIHNldA0KZGF0YV9zdWIgPC0gDQogIGRhdGFfc3ViICU+JSANCiAgc2VsZWN0KC1hdmFpbGFiaWxpdHlfNjAsIC1hdmFpbGFiaWxpdHlfOTAsIC1hdmFpbGFiaWxpdHlfMzY1KQ0KYGBgDQoNCiMjIENoZWNrIG1pc3NpbmcgZGF0YQ0KDQpXZSBoYXZlIGNyZWF0ZSBhIHRhYmxlIHRvIGluc3BlY3Qgd2l0aCB2YXJpYWJsZXMgaGF2ZSBtaXNzaW5nIGNhc2VzIGFuZCBob3cgbWFueS4gVGhlIHRhYmxlIHNob3dzIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0IHRoYXQgY29udGFpbiBtaXNzaW5nIHZhbHVlcyAoaW4gZGVzY2VuZGluZyBvcmRlcikuIFRoZSB0YWJsZSBzaG93cyB0aGF0IHRoZSB2YXJpYWJsZSAqc3F1YXJlX2ZlZXQqIGhhcyAkMTk2NjIkIG1pc3NpbmcgY2FzZXMsIHdoaWNoIGlzIGFib3V0ICQ5OC4xOVwlJC4gSWYgd2Ugd291bGQgZGVsZXRlZCB0aGUgbWlzc2luZyBjYXNlcywgdGhlIGRhdGEgc2V0IHdpbGwgYmFyZWx5IGNvbnRhaW4gYW55IGRhdGEuIE1vcmVvdmVyLCBvdGhlciBtZXRob2RzIGZvciBoYW5kbGluZyBtaXNzaW5nIHZhbHVlcyBsaWtlIHJlcGxhY2luZyBOQS12YWx1ZXMgd2l0aCB0aGUgbWVhbiBvciBtZWRpYW4gd291bGQgbm90IGJlIGFwcHJvcHJpYXRlIHNpbmNlIHRoZSB2YXJpYWJsZXMgd2lsbCBiZSBiYXNlZCBvbiBvbmx5ICQxLjgxXCUkIG9mIHRoZSBkYXRhLiBUaGVyZWZvcmUsICpzcXVhcmVfZmVldCogaXMgbm9nIGluY2x1ZGVkIGluIHRoZSBmaW5hbC4gVGhlIHZhcmlhYmxlICpob3N0X3Jlc3BvbnNlX3JhdGUqIGhhcyAkOTM0OSQgbWlzc2luZyBjYXNlcywgd2hpY2ggaXMgYWJvdXQgJDQ2LjY5XCUkLiBUaGUgdmFyaWFibGUgKmhvc3RfbmVpZ2hib3VyaG9vZCogaGFzICQ1OTcyJCwgd2hpY2ggaXMgYWJvdXQgJDI5LjgyXCUkLiBUaGUgdmFyaWFibGUgKmNsZWFuaW5nX2ZlZSogaGFzICQzNjA0JCwgd2hpY2ggaXMgYWJvdXQgJDE4LjAwXCUkLiBUaGUgdmFyaWFibGVzICAqaG9zdF9yZXNwb25zZV9yYXRlKiwgKmhvc3RfbmVpZ2hib3VyaG9vZCogYW5kICpjbGVhbmluZ19mZWUqIGRvIG5vdCBoYXZlIGFzIG1hbnkgbWlzc2luZyB2YWx1ZXMgYXMgKnNxdWFyZV9mZWV0KiwgaG93ZXZlciwgdGhlIHNhbWUgcmVhc29uaW5nIGFwcGxpZXMuIEFzIGEgcmVzdWx0LCB0aGVzZSB2YXJpYWJsZXMgYXJlIGFsc28gZXhjbHVkZWQgZnJvbSB0aGUgYW5hbHlzZXMuIA0KYGBge3IgTWlzc2luZyBkYXRhIGNoZWNrfQ0KIyBDb3VudCBtaXNzaW5nIGNhc2VzIHBlciB2YXJpYWJsZQ0KbmFfY291bnRlciA8LSBzYXBwbHkoZGF0YV9zdWIsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpDQp2YXJzIDwtIGNvbG5hbWVzKGRhdGFfc3ViKQ0KDQojIEV4dHJhY3QgYWxsIHZhcmlhYmxlcyB3aXRoIE5BLXZhbHVlcw0KbmFfdmFsdWVzIDwtIHRpYmJsZSh2YXJpYWJsZXMgPSB2YXJzLCBuYV9jb3VudCA9IG5hX2NvdW50ZXIpIA0KDQojIENoZWNrIG5hIGNvdW50IHBlciB2YXJpYWJsZQ0KbmFfdmFsdWVzICU+JQ0KICBmaWx0ZXIobmFfY291bnQgPiAwKSAlPiUNCiAgYXJyYW5nZShkZXNjKG5hX2NvdW50KSkNCmBgYA0KDQpNb3Jlb3Zlciwgd2UgaGF2ZSBjaGVjayBob3cgbWFueSBjYXNlcyBjb250YWluIG1pc3NpbmcgdmFsdWVzIGlmIHRoZSBvdGhlciB2YWx1ZXMgdGhhdCBoYXZlIG1pc3NpbmcgY2FzZXMgd291bGQgYmUgaW5jbHVkZWQgaW4gdGhlICdmaW5hbCcgZGF0YSBzZXQuIFRoZSB0YWJsZSBiZWxvdyBzaG93cyB0aGF0IHRoZXJlIGFyZSAyMDYgY2FzZXMgd2hpY2ggY29udGFpbiBtaXNzaW5nIHZhbHVlcywgd2hpY2ggaXMgYWJvdXQgJDEuMDNcJSQgb2YgdGhlIGVudGlyZSBkYXRhIHNldC4gU2luY2UgdGhpcyBpcyBhIHZlcnkgc21hbGwgcHJvcG9ydGlvbiBpdCBpcyBub3QgdmVyeSBsaWtlbHkgdGhhdCBkZWxldGluZyB0aGVzZSBjYXVzZXMgd291bGQgaGF2ZSBhIGxhcmdlIGltcGFjdCBvbiB0aGUgcHJlZGljdGlvbnMuIFRoZXJlZm9yZSwgd2UgZGVsZXRlIHRoZSBjYXNlcyB3aXRoIG1pc3NpbmcgdmFsdWVzLiANCmBgYHtyIEluY29tcGxldGUgY2FzZXN9DQojIENvbXB1dGUgaW5jb21wbGV0ZSByb3dzDQpkYXRhX3N1YiAlPiUgDQogIHNlbGVjdChob3N0X3NpbmNlLCBob3N0X3Jlc3BvbnNlX3RpbWUsIGhvc3RfbGlzdGluZ3NfY291bnQsDQogICAgICAgICBob3N0X2lkZW50aXR5X3ZlcmlmaWVkLCBiZWRzLCBiZWRyb29tcywgaG9zdF95ZWFyc19hY3RpdmUsIA0KICAgICAgICAgYmF0aHJvb21zKSAlPiUgDQogIGNvbXBsZXRlLmNhc2VzKCkgJT4lIA0KICBzdW1tYXJ5KGNvdW50KCkpDQpgYGANCg0KYGBge3IgR2VuZXJhdGUgZmluYWwgZGF0YSBzZXR9DQojIFNlbGVjdCB2YXJpYWJsZXMgZm9yIGRhdGEgc2V0DQp2YXJpYWJsZXNfYW5hbHlzaXMgPC0gICANCiAgbmFfdmFsdWVzICU+JSANCiAgZmlsdGVyKG5hX2NvdW50IDw9IDE1OCkgJT4lIA0KICBzZWxlY3QodmFyaWFibGVzKSAlPiUgDQogIHB1bGwodmFyaWFibGVzKQ0KDQojIENyZWF0ZSBmaW5hbCBkYXRhIHNldA0KZGF0YV9zZW1pX2ZpbmFsIDwtIGRhdGFfc3ViICU+JSBzZWxlY3QoYWxsX29mKHZhcmlhYmxlc19hbmFseXNpcykpDQpkYXRhX3NlbWlfZmluYWwgPC0gZGF0YV9zZW1pX2ZpbmFsICU+JSANCiAgc2VsZWN0KC1jKGFtZW5pdGllcywgYW1lbml0aWVzX2NsZWFuLCBob3N0X3ZlcmlmaWNhdGlvbnMsDQogICAgICAgICAgICBob3N0X3ZlcmlmaWNhdGlvbnNfY2xlYW4sIGhvc3Rfc2luY2UpKQ0KZGF0YV9maW5hbCA8LSBkYXRhX3NlbWlfZmluYWxbY29tcGxldGUuY2FzZXMoZGF0YV9zZW1pX2ZpbmFsKSwgXQ0KYGBgDQoNCiMgQ3JlYXRlIHRyYWluLXRlc3Qgc3BsaXQNCg0KRm9yIGZ1cnRoZXIgYW5hbHlzaXMgdGhlIGRhdGEgaXMgc3BsaXQgaW50byBhIHRyYWluLXRlc3Qgc2V0Lg0KYGBge3J9DQojIENyZWF0ZSBhIHRyYWluLXNwbGl0IHNldHMNCnNlZWRfeCA8LSAgMTIzDQpzZXQuc2VlZChzZWVkX3gpDQpkYXRhX3NwbGl0IDwtIGluaXRpYWxfc3BsaXQoZGF0YV9maW5hbCwgcHJvcCA9IDAuNykNCmRhdGFfdHJhaW4gPC0gdHJhaW5pbmcoZGF0YV9zcGxpdCkNCmRhdGFfdGVzdCA8LSB0ZXN0aW5nKGRhdGFfc3BsaXQpDQpgYGANCg0KIyBJbnNwZWN0aW5nIHRoZSBwcmVkaWN0ZWQgdmFyaWFibGUNCg0KSW4gb3JkZXIgdG8gcHJldmVudCBkYXRhIGxlYWthZ2VzIHdlIG9ubHkgaW5zcGVjdCB0aGUgcHJlZGljdGVkIHZhcmlhYmxlICpwcmljZSogaW4gdGhlIHRyYWluaW5nIHNldC4gSW4gb3JkZXIgdG8gaW5zcGVjdCAqcHJpY2UqIHdlIGhhdmUgY3JlYXRlZCBhIGRpc3RyaWJ1dGlvbiBwbG90LiBUaGUgcGxvdCBzaG93cyB0aGF0IHRoZSBkYXRhIHNldCBjb250YWlucyBzb21lIG91dGxpZXJzIGFuZCB0aGF0IHRoZSBkaXN0cmlidXRpb24gaXMgcmlnaHRseSBza2V3ZWQuIEJvdGggdGhlIG91dGxpZXJzIGFuZCB0aGUgc2tld2VuZXNzIG1ha2UgdGhlIGRhdGEgbGVzcyBpbnRlcnByZXRhYmxlIGFuZCB0aGlzIGNvdWxkIGhhdmUgYW4gaW5mbHVlbmNlIG9uIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbHMuIA0KYGBge3J9DQojIFBsb3QgZGlzdHJpYnV0aW9uIHByaWNlDQpnZ3Bsb3QoZGF0YSA9IGRhdGFfdHJhaW4gLCBhZXMocHJpY2UpKSArDQogIGdlb21faGlzdG9ncmFtKGNvbD0iYmxhY2siLA0KICAgICAgICAgICAgICAgICBicmVha3M9c2VxKDAsIG1heChkYXRhX3RyYWluJHByaWNlKSwgYnk9NzUpLA0KICAgICAgICAgICAgICAgICBhZXMoZmlsbD0uLmNvdW50Li4pKSArDQogIGxhYnModGl0bGU9Ikhpc3RvZ3JhbSBmb3IgUHJpY2UiLCB4PSJQcmljZSIsIHk9IkNvdW50IikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KCJDb3VudCIsIGxvdz0iZ3JlZW4iLCBoaWdoPSJyZWQiKQ0KYGBgDQoNCkluIG9yZGVyIHRvIHByZXZlbnQgdGhpcyBwb3RlbnRpYWwgcHJvYmxlbXMgd2UgaGF2ZSBjcmVhdGVkIGEgbmV3IGRpc3RyaWJ1dGlvbiBwbG90IHdpdGggYSBsb2cgdHJhbnNmb3JtZWQgdmFyaWFibGUgKnByaWNlKi4gVGhlIHBsb3Qgc2hvd3MgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIGlzIGxlc3Mgc2tld2VkIGFuZCBkb2VzIG5vdCBjb250YWluIGFueSBsYXJnZSBvdXRsaWVycy4gUmVzdWx0aW5nLCB0aGUgZGF0YSB0aGF0IGlzIG1vcmUgaW50ZXJwcmV0YWJsZS4gVGhlcmVmb3JlLCBsb2cgdHJhbnNmb3JtaW5nIHdlIHdpbGwgdXNlIHRoZSBsb2cgdHJhbnNmb3JtZWQgKnByaWNlKiBmb3Igb3VyIG1vZGVscy4gDQpgYGB7cn0NCiMgUGxvdCBkaXN0cmlidXRpb24gcHJpY2UNCmdncGxvdChkYXRhID0gZGF0YV90cmFpbiAsIGFlcyhsb2cocHJpY2UgKyAxKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sPSJibGFjayIsDQogICAgICAgICAgICAgICAgIGFlcyhmaWxsPS4uY291bnQuLikpICsNCiAgbGFicyh0aXRsZT0iSGlzdG9ncmFtIGZvciBMbiBQcmljZSIsIHg9IkxuIFByaWNlIiwgeT0iQ291bnQiKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoIkNvdW50IiwgbG93PSJncmVlbiIsIGhpZ2g9InJlZCIpDQpgYGANCg0KYGBge3J9DQojIExvZyB0cmFuc2Zvcm0gdGhlIHByaWNlIGluIGZvciBib3RoIHRyYWluaW5nIGFuZCB0ZXN0IHNldA0KZGF0YV9maW5hbCRwcmljZSA8LSBsb2coZGF0YV9maW5hbCRwcmljZSArIDEpDQoNCiMgUmVzcGxpdCB0aGUgZGF0YSB1c2luZyB0aGUgc2FtZSBzZWVkIA0Kc2V0LnNlZWQoc2VlZF94KQ0KZGF0YV9zcGxpdCA8LSBpbml0aWFsX3NwbGl0KGRhdGFfZmluYWwsIHByb3AgPSAwLjcpDQpkYXRhX3RyYWluIDwtIHRyYWluaW5nKGRhdGFfc3BsaXQpDQpkYXRhX3Rlc3QgPC0gdGVzdGluZyhkYXRhX3NwbGl0KQ0KDQpgYGANCg0KIyBLLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiANCg0KTW9yZW92ZXIsIHdlIGhhdmUgZ2VuZXJhdGVkIDEwLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiBzZXRzLg0KYGBge3J9DQojIEdlbmVyYXRlIDEwLWZvbGQgQ1Ygc2V0cw0Kc2V0LnNlZWQoMzIxKQ0KZGF0YV9mb2xkcyA8LSB2Zm9sZF9jdihkYXRhX3RyYWluLCB2ID0gMTApDQpkYXRhX2ZvbGRzDQpgYGANCg0KIyBSZW1vdmUgZGF0YSBmcmFtZXMgdG8gYXZvaWQgbGVha2FnZXMgYW5kIGVycm9ycw0KYGBge3J9DQpybShkYXRhKQ0Kcm0oZGF0YV9zdWIpDQpybShkYXRhX3NlbWlfZmluYWwpDQpybShuYV92YWx1ZXMpDQpgYGANCg0KDQo=